<template>
  <div>
    <a-upload-dragger
      v-show="showUpload"
      :accept="accept"
      :customRequest="customRequest"
      :showUploadList="false"
      @reject="rejectNotAccept"
    >
      <div style="padding: 45px;">
        <p class="ant-upload-drag-icon">
          <a-icon type="plus" />
        </p>
        <p class="ant-upload-text">
          点击或拖拽文件到这里上传
        </p>
        <p class="ant-upload-hint">
          <span v-html="remark"></span>
        </p>
        <p v-if="errorTypeStatus" style="font-size: 12px;color: red;margin-top: 10px;">
          {{ errorTypeText }}
        </p>
      </div>
    </a-upload-dragger>

    <div class="percent-wrapper" v-show="!showUpload">
      <span class="file-name">{{ fileName }}</span>
      <a-progress :percent="percent" :status="percentStatus" />
      <span v-if="percentStatus === 'exception'" class="temp-exception">{{ templateException }}</span>
      <span v-if="percentStatus === 'exception' || percentStatus === 'success'" class="temp-reupload" @click="reUpload"><a>重新上传</a></span>
    </div>
  </div>
</template>

<script>
import md5 from 'js-md5'
import { checkFileChunk, doUpload } from '@/api/modular/main/baseIndex/fileChunkUpload'
import { concurrentExecution } from '@/utils/util'
export default {
  name: 'upload',
  props: {
    accept: {
      type: String,
      default: '.zip,.xls,.xlsx,.csv'
    },
    remark: {
      type: String,
      default: `支持Excel、CSV表格文件，及.zip压缩的shapefile文件<br>（支持断点续传）`
    },
    concurrent: {
      type: Number,
      default: 5
    },
    chunkSize: {
      type: Number, // 单位 byte
      default: 2 * 1024 * 1024 // 2MB一片
    }
  },
  data() {
    return {
      chunkCount: 0,
      file: null,
      fileType: '',
      fileMD5: '',
      uploaded: [], // 已经上传的
      chunkList: [], // 分片列表
      percent: 0,
      percentStatus: 'active',
      showUpload: true,
      errorTypeText: '',
      errorTypeStatus: false,
      fileName: '',
      templateException: ''
    }
  },
  methods: {
    md5,
    reUpload() {
      this.reset()
    },
    customRequest(data) {
      const _that = this
      this.fileName = data.file.name
      this.file = data.file
      console.log(this.file)
      this.fileType = this.file.name.substring(this.file.name.lastIndexOf('.') + 1, this.file.name.length)
      this.chunkCount = Math.ceil(this.file.size / this.chunkSize) // 总片数
      this.chunkList = [] // 分片列表
      this.uploaded = []
      this.showUpload = false
      this.errorTypeStatus = false
      console.log('获取文件的MD5值')
      const fileReaderInstance = new FileReader()
      fileReaderInstance.readAsBinaryString(this.file)
      fileReaderInstance.addEventListener('load', e => {
        console.log('e:', e)
        const fileBolb = e.target.result
        _that.fileMD5 = this.md5(fileBolb)
        console.log('fileMD5:', _that.fileMD5)
        const form = new FormData()
        form.append('filename', _that.file.name)
        form.append('identifier', _that.fileMD5)
        form.append('objectType', _that.fileType)
        form.append('chunkNumber', 1)
        checkFileChunk(form).then(res => {
          console.log(res)
          if (res.success) {
            if (res.data.skipUpload) {
              this.$message.warning('文件已被上传')
              _that.reset()
            } else {
              if (res.data.uploaded && res.data.uploaded.length !== 0) {
                _that.uploaded = [].concat(res.data.uploaded)
              }
              console.log('已上传的分片：', _that.uploaded)
              if (_that.chunkCount === 1 || _that.concurrent === 1) {
                console.log('顺序上传')
                _that.sequentialUpload(0)
              } else {
                console.log('并发上传')
                _that.concurrentUpload()
              }
            }
          }
        }).catch((e) => {
          console.error('文件合并错误:', e)
        })
      })
    },
    /**
     * 顺序上传
     */
    sequentialUpload(currentChunk) {
      const _that = this
      const { chunkCount } = this
      const { chunk } = this.getChunkInfo(this.file, currentChunk, this.chunkSize)
      const chunkInfo = {
        chunk,
        currentChunk,
        chunkCount
      }
      const sd = parseInt((chunkInfo.currentChunk / chunkInfo.chunkCount) * 100)
      _that.percent = sd
      console.log('上传进度：', sd)
      console.log('当前上传分片：', currentChunk)
      const index = currentChunk + 1
      if (this.uploaded.indexOf(index + '') > -1) {
        console.log('分片【' + currentChunk + '】已上传')
        this.sequentialUpload(currentChunk + 1)
      } else {
        const uploadData = this.createUploadData(chunkInfo)
        doUpload(uploadData).then(res => {
          if (res.success) {
            _that.uploaded.push(chunkInfo.currentChunk + 1)
            if (_that.uploaded.length === chunkInfo.chunkCount) {
              console.log('全部完成')
              _that.percent = 100
              _that.percentStatus = 'success'
              this.$emit('success', {
                fileName: res.data.fileName,
                fileType: _that.fileType,
                filePath: res.data.filePath,
                identifier: res.data.identifier,
                size: _that.file.size
              })
            } else {
              _that.sequentialUpload(currentChunk + 1)
            }
          } else {
            _that.percentStatus = 'exception'
          }
        }).catch(() => {
          _that.percentStatus = 'exception'
        })
      }
    },
    /**
     * 并发上传
     */
    concurrentUpload() {
      for (let i = 0; i < this.chunkCount; i++) {
        this.chunkList.push(Number(i))
      }
      console.log('需要上传的分片列表：', this.chunkList)
      const _that = this
      concurrentExecution(this.chunkList, this.concurrent, (curItem) => {
          return new Promise((resolve, reject) => {
            const { chunkCount } = this
            const { chunk } = _that.getChunkInfo(_that.file, curItem, _that.chunkSize)
            const chunkInfo = {
              chunk,
              currentChunk: curItem,
              chunkCount
            }
            const sd = parseInt((chunkInfo.currentChunk / chunkInfo.chunkCount) * 100)
            _that.percent = sd
            console.log('上传进度：', sd)
            console.log('当前上传分片：', chunkInfo.currentChunk)
            const index = chunkInfo.currentChunk + 1
            if (_that.uploaded.indexOf(index + '') === -1) {
              const uploadData = _that.createUploadData(chunkInfo)
              doUpload(uploadData).then(res => {
                if (res.success) {
                  _that.uploaded.push(chunkInfo.currentChunk + 1)
                  console.log('已经上传完成的分片：', _that.uploaded)
                  // 判断是否全部上传完
                  if (_that.uploaded.length === chunkInfo.chunkCount) {
                    _that.percent = 100
                    _that.percentStatus = 'success'
                    console.log('上传进度：', 100)
                    this.$emit('success', {
                      fileName: res.data.fileName,
                      fileType: _that.fileType,
                      filePath: res.data.filePath,
                      identifier: res.data.identifier,
                      size: _that.file.size
                    })
                  }
                  resolve()
                } else {
                  reject(res)
                  _that.percentStatus = 'exception'
                  console.error(res.message)
                }
              }).catch(err => {
                reject(err)
                _that.percentStatus = 'exception'
                console.error(err)
              })
            } else {
              console.log('分片【' + chunkInfo.currentChunk + '】已上传')
              resolve()
            }
          })
      }).then(res => {
        console.log('finish', res)
      })
    },
    /**
     * 获取每一个分片的详情
     */
    getChunkInfo(file, currentChunk, chunkSize) {
      const start = currentChunk * chunkSize
      const end = Math.min(file.size, start + chunkSize)
      const chunk = file.slice(start, end)
      return {
        start,
        end,
        chunk
      }
    },
    createUploadData(chunkInfo) {
      const fetchForm = new FormData()
      fetchForm.append('identifier', this.fileMD5)
      fetchForm.append('chunkNumber', chunkInfo.currentChunk + 1)
      fetchForm.append('chunkSize', this.chunkSize)
      fetchForm.append('currentChunkSize', chunkInfo.chunk.size)
      const chunkfile = new File([chunkInfo.chunk], this.file.name)
      fetchForm.append('file', chunkfile)
      fetchForm.append('filename', this.file.name)
      fetchForm.append('totalChunks', chunkInfo.chunkCount)
      fetchForm.append('totalSize', this.file.size)
      fetchForm.append('objectType', this.fileType)
      return fetchForm
    },
    rejectNotAccept(fileList) {
      console.log(fileList)
      if (fileList && fileList.length > 0) {
        const file = fileList[0]
        const type = file.type
        this.errorTypeText = '不支持' + type + '类型的文件'
        this.errorTypeStatus = true
      }
    },
    reset() {
      this.showUpload = true
      this.chunkCount = 0
      this.file = null
      this.fileType = ''
      this.fileMD5 = ''
      this.uploaded = []
      this.chunkList = []
      this.percent = 0
      this.percentStatus = 'active'
      this.errorTypeText = ''
      this.errorTypeStatus = false
      this.fileName = ''
      this.templateException = ''
    }
  }
}
</script>

<style scoped lang="less">
.ant-upload-drag-icon {
  margin: 29px 0 20px 0;
}

.percent-wrapper {
  background: #fafafa;
  border: 1px dashed #d9d9d9;
  border-radius: 2px;
  padding: 93px 50px 94px;
  text-align: center;
}

.file-name {
  color: rgba(0, 0, 0, 0.4);
}
.temp-exception {
  color: red;
  font-size: 12px;
}
span.temp-reupload {
  margin-left: 10px;
  font-size: 12px;
}
</style>
